using System;
using System.Text;
using CalcSharp.Core;

namespace CalcSharp
{
    #region number system conversion
    sealed class Converter
    {
        private Converter() { }
        
        public static long base2int64(int basen, string reprez)
        {
            return Convert.ToInt64(reprez, basen);
        }

        public static float hexa2float(string reprez)
        {
            string[] rawbytes = MiscCoreFuncts.split(reprez, 2);
            if (rawbytes.Length < 4 || rawbytes.Length > 4) throw new CSException("Cant't parse input as a float");
            byte[] bytes = new byte[4];
            for (int i = 0; i < rawbytes.Length; i++) bytes[i] = Convert.ToByte(rawbytes[i], 16);
            return BitConverter.ToSingle(bytes, 0);
        }

        public static double hexa2double(string reprez)
        {
            string[] rawbytes = MiscCoreFuncts.split(reprez, 2);
            if (rawbytes.Length < 8 || rawbytes.Length > 8) throw new CSException("Cant't parse input as a double");
            byte[] bytes = new byte[8];
            for (int i = 0; i < rawbytes.Length; i++) bytes[i] = Convert.ToByte(rawbytes[i], 16);
            return BitConverter.ToDouble(bytes, 0);
        }

        public static string bytearray2string(byte[] array, int sys)
        {
            StringBuilder sb = new StringBuilder();
            int len = 0;
            switch (sys)
            {
                case 2:
                    len = 8;
                    break;
                case 8:
                    len = 3;
                    break;
                case 16:
                    len = 2;
                    break;
            }
            string tmp;
            foreach (byte b in array)
            {
                tmp = Convert.ToString(b, sys);
                if (tmp.Length < len)
                {
                    for (int i = 0; i < (len - tmp.Length); i++) sb.Append("0");
                    sb.Append(tmp);
                }
                else sb.Append(tmp);
            } 
            return sb.ToString();
        }

        public static string conv(string inp, string outp, string num)
        {
            long ltemp;
            float ftemp;
            double dtemp;

            if (outp != "2" && outp != "8" && outp != "10" && outp != "16" && outp != "16F" && outp != "16D")
            {
                throw new CSException("Not supported number system. Supoteds are: 2,8,10,16,16f,16d");
            }
            switch (inp)
            {
                case "10":
                    if (outp == "16F")
                    {
                        ftemp = (float)MiscFuncts.parsestr(num);
                        return bytearray2string(BitConverter.GetBytes(ftemp), 16);
                    }
                    else if (outp == "16D")
                    {
                        dtemp = MiscFuncts.parsestr(num);
                        return bytearray2string(BitConverter.GetBytes(dtemp), 16);
                    }
                    else
                    {
                        long t = Convert.ToInt64(MiscFuncts.parsestr(num));
                        ltemp = base2int64(Convert.ToInt32(inp), t.ToString());
                        return Convert.ToString(ltemp, Convert.ToInt32(outp));
                    }
                case "2":
                case "8":
                case "16":
                    ltemp = base2int64(Convert.ToInt32(inp), num);
                    return Convert.ToString(ltemp, Convert.ToInt32(outp));
                case "16F":
                    ftemp = hexa2float(num);
                    if (outp == "10") return ftemp.ToString();
                    else if (outp == "16D")
                    {
                        dtemp = Convert.ToDouble(ftemp);
                        return bytearray2string(BitConverter.GetBytes(dtemp), 16);
                    }
                    else return bytearray2string(BitConverter.GetBytes(ftemp), Convert.ToInt32(outp));
                case "16D":
                    dtemp = hexa2double(num);
                    if (outp == "10") return dtemp.ToString();
                    else if (outp == "16F")
                    {
                        ftemp = Convert.ToSingle(dtemp);
                        return bytearray2string(BitConverter.GetBytes(ftemp), 16);
                    }
                    else return bytearray2string(BitConverter.GetBytes(dtemp), Convert.ToInt32(outp));
                default:
                    throw new CSException("Not supported number system. Supoteds are: 2,8,10,16,16f,16d");
            }
        }
    }
    #endregion
}